<template>
	<div class="upload-container">
		<uploadAttachment v-if="isDialog" ref="attachmentRef" :accept="accept" :limit="limit" :size="size" type="image" @confirm="uploadConfirm" />
		<template v-else>
			<el-upload
				ref="uploadRef"
				:action="uploadData.action"
				:headers="uploadData.headers"
				:data="uploadData.params"
				:multiple="limit > 1 ? true : false"
				:disabled="disabled"
				:accept="accept"
				:limit="limit"
				:show-file-list="false"
				:before-upload="handleBeforeUpload"
				:on-change="handleChange"
				:on-success="handleSuccess"
				:on-exceed="handleExceed"
				:on-error="handleError"
			/>
		</template>
		<template v-if="limit > 1 && imageList.data.length">
			<div v-for="(item, index) in imageList.data" :key="index" class="upload-box" :style="style">
				<el-image :src="getUrl(item)" class="upload-image" fit="contain" />

				<div class="close-icon" @click="deleteImg(index)" v-if="!disabled">
					<SvgIcon name="ele-Close" size="12" />
				</div>

				<div class="upload-handle">
					<div class="handle-icon" @click="previewImage(index)">
						<SvgIcon name="ele-ZoomIn" size="20" />
					</div>
				</div>
			</div>
		</template>
		<div class="upload-box" :style="style">
			<div
				class="upload-empty cursor-pointer"
				@click="uploadImageBtn"
				v-show="imageList.data.length < 1 || (limit > 1 && imageList.data.length < limit)"
				v-if="!disabled"
			>
				<SvgIcon name="ele-Plus" size="15" class="avatar-uploader-icon" />
				<div>上传图片</div>
			</div>
			<div class="upload-empty cursor-pointer" v-show="imageList.data.length < 1 || (limit > 1 && imageList.data.length < limit)" v-else>
				<SvgIcon name="local-icon-image-disabled" size="15" class="w-[20px] h-[20px]" />
				<div>上传禁用</div>
			</div>
			<template v-if="limit == 1 && imageList.data.length">
				<el-image :src="getUrl(imageList.data[0])" class="upload-image" fit="contain" />
				<div class="close-icon" @click="deleteImg(0)" v-if="!disabled">
					<SvgIcon name="ele-Close" size="12" />
				</div>
				<div class="upload-handle">
					<div class="handle-icon" @click="editImg" v-if="!disabled">
						<SvgIcon name="ele-Edit" class="mb-0" size="20" />
					</div>
					<div class="handle-icon" @click="previewImage(0)">
						<SvgIcon name="ele-ZoomIn" class="mb-0" size="20" />
					</div>
				</div>
			</template>
		</div>
	</div>
	<div class="el-upload__tip upload-tip-text">{{ promptText }}</div>
	<el-image-viewer
		v-if="previewView.visible"
		@close="previewView.visible = false"
		:url-list="previewImageList"
		:initial-index="previewView.index"
		:zoom-rate="1"
	/>
</template>
<script lang="ts" setup>
import { computed, reactive, ref, watch, toRaw } from 'vue';
import { messageError } from '/@/utils/message';
import type { UploadInstance } from 'element-plus';
import { Local } from '/@/utils/storage';
import { getUrl, getFileOrder } from '/@/utils/util';

const { VITE_API_URL } = import.meta.env;

const props = defineProps({
	modelValue: {
		type: String,
		required: true,
		default: '',
	},
	// 是否弹框打开
	isDialog: {
		type: Boolean,
		required: false,
		default: true,
	},
	// 提示文字
	promptText: {
		type: String,
		required: false,
		default: '',
	},
	// 是否禁用
	disabled: {
		type: Boolean,
		required: false,
		default: false,
	},
	// 限制上传数量
	limit: {
		default: 1,
		required: false,
		type: Number,
	},
	// 接受上传的图片类型
	accept: {
		type: String,
		required: false,
		default: '.png,.gif,.jpg,.jpeg',
	},
	// 限制上传大小，单位:kb
	size: {
		type: Number,
		required: false,
		default: 1000,
	},
	// 上传文件名称
	name: {
		type: Number,
		required: false,
		default: '',
	},
	// 上传文件目录
	saveDir: {
		type: String,
		required: false,
		default: '',
	},
	// 长度
	width: {
		type: String,
		default: '80px',
	},
	// 高度
	height: {
		type: String,
		default: '80px',
	},
});

const emit = defineEmits(['update:modelValue', 'change']);

const imageValue = computed({
	get() {
		return props.modelValue;
	},
	set(value) {
		emit('update:modelValue', value);
	},
});

const attachmentRef = ref(null);

const imageList = reactive({
	data: [],
});

const uploadRef = ref<UploadInstance>();

const uploadData = reactive({
	action: `${VITE_API_URL}/admin/upload/image`,
	params: <any>{},
	headers: {
		Authorization: Local.get('token'),
	},
});

let previewImageList: string[] = reactive([]);

const previewView = reactive({
	visible: false,
	index: 0,
});

const setValue = () => {
	imageValue.value = toRaw(imageList.data).toString();
	previewImageList = toRaw(imageList.data).map((url: string) => {
		return getUrl(url);
	});
};

watch(
	() => imageValue.value,
	() => {
		imageList.data = [
			...imageValue.value.split(',').filter((item: string) => {
				return item;
			}),
		];
		setValue();
	},
	{ immediate: true }
);

// 上传图片
const uploadImageBtn = () => {
	if (!props.disabled) {
		if (props.isDialog) {
			attachmentRef.value.openDialog();
		} else {
			uploadRef.value.$el.querySelector('input').click();
		}
	}
};

// 附件组件选择完成
const uploadConfirm = (data: Record<string, any>) => {
	if (props.limit == 1) {
		imageList.data.splice(0, 1);
		data && imageList.data.push(data.url);
	} else {
		const data_order = getFileOrder(data); //重新排序
		const image_order = [];
		data_order.forEach((item) => {
			image_order.push(item.url);
		});
		if (imageList.data.length < props.limit) {
			imageList.data.push(...image_order.slice(0, props.limit - imageList.data.length));
		}
	}
	setValue();
	emit('change', imageValue.value);
};

// 上传之前
const handleBeforeUpload = () => {
	if (props.accept && props.accept != '*/*') uploadData.params['ext'] = props.accept.split('.').join('');
	if (props.size) uploadData.params['size'] = props.size * 1024;
	if (props.name) uploadData.params['name'] = props.name;
	if (props.saveDir) uploadData.params['save_dir'] = props.saveDir;
};

// 上传检验
const handleChange = (file: any, fileLists: any[]) => {
	if (file.status !== 'ready') return;
	let rawFile = file.raw;
	let imgSize = rawFile.size / 1024;
	let imgType = rawFile.type;
	let acceptArr = props.accept.split('.').join('').split(',');

	if (!acceptArr.includes(imgType.substring(imgType.lastIndexOf('/') + 1, imgType.length))) {
		messageError('上传图片格式不符！');
		fileLists.splice(-1, 1);
		return false;
	}
	if (props.size && imgSize > props.size) {
		messageError('图片大小不能超过' + props.size + 'KB!');
		fileLists.splice(-1, 1);
		return false;
	}
	if (imageList.data.length + fileLists.length > props.limit) {
		if(props.isDialog) {
			fileLists.splice(-1, 1);
			return false;
		} else {
			imageList.data.splice(-1, 1);
		}
	}
};

// 上传成功
const handleSuccess = (response: any, file: any, fileLists: any[]) => {
	const allSuccess = fileLists.every((item) => item.status == 'success');
	if (allSuccess) {
		uploadRef.value?.clearFiles();
	}

	if (response.code == 0) {
		if (props.limit == 1) imageList.data.splice(0, 1);
		if (imageList.data.length < props.limit) imageList.data.push(response.data.url);
	} else {
		fileLists.splice(-1, 1);
		messageError(response.msg);
	}
	setValue();
	emit('change', imageValue.value);
};

// 上传提示
const handleExceed = () => {
	messageError(`最多可以上传${props.limit}张图片`);
};

// 上传错误
const handleError = (event: any, file: any) => {
	messageError(`${file.name}图片上传失败`);
	uploadRef.value?.abort(file);
};

// 编辑图片
const editImg = () => {
	if (props.isDialog) {
		attachmentRef.value.openDialog();
	} else {
		uploadRef.value.$el.querySelector('input').click();
	}
};

// 删除图片
const deleteImg = (index) => {
	imageList.data.splice(index, 1);
	setValue();
};

// 预览图片
const previewImage = (index) => {
	previewView.visible = true;
	previewView.index = index;
};

// 自定义样式
const style = computed(() => {
	return {
		width: props.width,
		height: props.height,
	};
});

defineExpose({
	deleteImg
});
</script>
<style lang="scss" scoped>
.upload-container {
	display: flex;
	justify-content: left;
	width: 100%;
	flex-wrap: wrap;

	.upload-box {
		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		width: 80px;
		height: 80px;
		transition: var(--el-transition-duration-fast);
		margin-right: 10px;
		margin-bottom: 7px;
		.upload-image {
			width: 100%;
			height: 100%;
			object-fit: contain;
			box-sizing: border-box;
			position: relative;
			border-radius: 4px;
			overflow: hidden;
			border-width: 1px;
			border-color: var(--el-border-color-extra-light);
			background-color: var(--el-border-color-extra-light);
		}
		.upload-empty {
			position: relative;
			display: flex;
			flex-direction: column;
			align-items: center;
			justify-content: center;
			box-sizing: border-box;
			border: 1px dashed var(--el-border-color-darker);
			width: 100%;
			height: 100%;
			border-radius: 0.25rem;
			font-size: 12px;
			color: var(--el-text-color-secondary);
			.el-icon.avatar-uploader-icon {
				font-size: 25px;
				color: rgba(0, 0, 0, 0.45);
				text-align: center;
			}

			.el-icon.avatar-uploader-icon svg {
				height: 1em;
				width: 1em;
			}
		}
		.upload-empty:hover {
			border-color: var(--el-color-primary);
		}
		.upload-handle {
			position: absolute;
			bottom: 0;
			right: 0;
			box-sizing: border-box;
			display: none;
			align-items: center;
			justify-content: center;
			width: 100%;
			height: 40%;
			cursor: pointer;
			background: rgb(0 0 0 / 30%);
			opacity: 0;
			transition: var(--el-transition-duration-fast);
			color: #fff;
			border-radius: 0.25rem;

			.handle-icon {
				display: flex;
				flex-direction: column;
				align-items: center;
				justify-content: center;
				padding: 0 6%;
				color: aliceblue;
				.el-icon {
					font-size: 130%;
					line-height: 130%;
				}
			}
		}
		.close-icon {
			display: none;
			position: absolute;
			top: -6px;
			right: -6px;
			width: 16px;
			height: 16px;
			background-color: #0000004d;
			justify-content: center;
			align-items: center;
			border-radius: 50%;
			color: #fff;
			cursor: pointer;
		}
		&:hover {
			.upload-handle {
				display: flex;
				opacity: 1;
			}
			.close-icon {
				display: flex;
			}
		}
	}
}

.upload-tip-text {
	color: #999;
	margin-top: 0;
}
</style>
